
#ifndef _OPENGLFRAME_H_
#define _OPENGLFRAME_H_

#include <QtOpenGL/QGLWidget>
#include <QtGui>

#include "../meshdef/cgaltypes.h"
#include "../enumtypes.h"
//~ #include "../core/typedefs.h"
#include "../core/constraints.h"

#include "../arcball.h"
#include "../selection.h"
#include "../texture.h"
#include "../glDrawFunctions.h"
#include "../meshdef/mesh.h"
#include "../meshdef/deformationMesh.h"

#include <vector>
#include <list>
#include <map>
#include <algorithm>

using namespace std;

enum InteractionMode {VIEW_MODE, SELECT_MODE};
enum InputActions {ADD_CONSTRAINTS, ADD_BARRIERS};

/// A wrapper over QGLWidget.
class OpenGLFrame: public QGLWidget {
   
   Q_OBJECT
   
public:
   /// Constructor.
   OpenGLFrame (QWidget* parent=0, const QGLWidget* shareWidget = 0, Qt::WFlags f=0);
   ~OpenGLFrame();
   
   /// Sets the interaction mode
   void setInteractionMode (InteractionMode m);
   
   /// It sets the projection/modelview matrices
   void setGLview(); 
   
   void meshRenderMode(MeshRenderMode mrm)      { meshrendermode_mask = mrm; }
   void viewItemOn(ViewItems v)                 { viewitems_mask = viewitems_mask | v; } // inclusive-OR
   void viewItemOff(ViewItems v)                { viewitems_mask = viewitems_mask ^ v; } // exclusive-or
   void lightingOnOff(bool l)                   { is_lightingOn = l; }
   bool isProjectionOrtho()                     { return isProjOrtho; }
   void orthographic(bool o) { 
      (o)?(isProjOrtho=true):(isProjOrtho=false);
   }
   
   void inputAction(InputActions a) { in_actions = a; }
   
   /// Loads a new shape from a file. 
   /// @param filename name of file in off format.
   /// @return true if polyhedron loading was successful.
   bool loadShape(const QString& filename);
   
   void computeDeformation();
   
   /// Update the mesh with its deformed vertex positions
   void updateMesh();
   
   /// Clear the data scene
   void clear();
   
protected:
   
   /// OpenGL initialization
   void initializeGL();
   /// Drawing callback
   void paintGL();
   
   /// Resize callback.
   /// @param width the width of the new window.
   /// @param height the height of the new window.
   void resizeGL(int width, int height);
   
   /// Returns the world coordinates of a point in screen space
   /// using a orthographic projection
   /// @param p input point in world space
   /// @return point in screen space
   Point screenToWorld(Point p);
   
   /// Returns the world coordinates of a point in screen space
   /// using a orthographic projection
   /// @param p input point in world space
   /// @return point in screen space
   Point screenToWorldOrtho(Point p);
   
   /// Mouse callback functions
   void mousePressEvent(QMouseEvent *e);
   void mouseMoveEvent(QMouseEvent *e);
   void mouseReleaseEvent(QMouseEvent *e);
   void wheelEvent(QWheelEvent *e);
   void keyPressEvent(QKeyEvent *e);
   
public slots:
   /// Zoom in operation.
   void zoomIn ();
   /// Zoom out operation.
   void zoomOut ();
   /// Zoom All operation.
   void zoomAll ();
   
private:
   void genWorldLimits();
   void drawFloor();
   /// This function is from http://www.devmaster.net community.
   void glShadowProjection(float *l, float *e, float *n);
   /// Draws the objects in selection mode
   void paintGLselection();

   /// Sets the interaction mode
   InteractionMode        interactionMode;
   /// Position of 3D cursor
   Point cursor3D;
   /// Scene tranformation
   Transformation sceneTransform;
   /// Temp transformations used for mouse tracking
   Transformation objectToScene, sceneToObject;
   /// Temp vectors used for mouse tracking
   Vector pixelDisplacement[2];
   Point grabStart, grabLast;
   
   /// An arcball object
   ArcBall                 arcball;
   float                   tM[16];   // transformation matrix
   Texture                 *texConstraints;
   Texture                 *texFloor;
   
private:
   bool                                is_lightingOn;
   bool                                isProjOrtho;     // true when projection is perspective. false when perspective
   int                                 meshrendermode_mask;
   unsigned                            viewitems_mask;
   InputActions                        in_actions;
   
   /// opengl data
   float                               fovy;         // Specifies the field of view angle, in degrees, in the y direction
   float                               zoomFactor;   // zoom factor
   float                               cameye[3];    // camera's eye
   float                               camcenter[3]; // Specifies the position of the reference point
   float                               mincoo[3];    // minimum point coordinates of the GL world
   float                               maxcoo[3];    // maximum point coordinates of the GL world
   GLdouble                            mMtx[16], pMtx[16];  /// modelview/projection matrix
   GLint                               viewport[4];         /// the viewport
   float                               WorldWidth;
   float                               WorldHeight;
   float                               objDistance;
   float                               nearplane;
   float                               farplane;
   
   /// time info
   float                               cfps;
   float                               lastTime;
   time_t                              start, end;
   unsigned                            frame;
   
   /// /////////////////////////////////////////////
   Mesh                                *model;
   DeformationMesh                     *deformer;
   Constraints                          constraints;
   Selection                            selection;
   bool                                 on_deformation;
   uint                                 id_moving;
   
   list<list<Halfedge_handle> >         rings;
};

#endif
